﻿#include "CanvasWidget.h"
#include "Render/Widget/RenderWidgets.h"
#include "Texture/Texture2D.h"

#include "Framework/Application.h"
#include "Font/FontSubsystem.h"

#include "Time/CPUTimeCounter.h"

void RCanvasWidget::PaintSelf(uint16_t &InZOrder, const SRect &InClipArea)
{
    CODE_BLOCK_TIME_COUNT(U"绘制画布控件")

    BEGIN_CODE_BLOCK_TIME_COUNT(U"准备画布绘制项")
    OnPaint.Broadcast();
    END_CODE_BLOCK_TIME_COUNT()

    // TVector<std::shared_ptr<CCanvasItem>> AllRenderItems;
    // AllRenderItems.Reserve(Items.Num()*2);
    // for(auto& Item:Items)
    // {
    //     auto RenderItem=Item->GetRenderItem();
    //     AllRenderItems.Add(RenderItem);

    //     RenderItem->ZOrder=InZOrder;
    //     InZOrder++;
    // }


    // auto RenderCanvasWidget=GetRenderCanvasWidget();
    // RenderCanvasWidget->SetItems(AllRenderItems);

    // RenderCanvasWidget->SetClipRect(InClipArea);
    // RenderCanvasWidget->SetRect(SRect(PresentAbsPosition,PresentSize));

    // PaintRenderWidget(RenderCanvasWidget);

    for(auto& Item:Items)
    {
        if(Item->IsA<RCanvasLineItem>())
        {
            CODE_BLOCK_TIME_COUNT(U"绘制线段")

            TSharedObjectPtr<RCanvasLineItem> Line=Item;
            auto LineItem=std::make_shared<SRenderLineWidget>();
            LineItem->Start=Line->Start;
            LineItem->End=Line->End;
            LineItem->Width=Line->LineWidth;
            LineItem->Color=Line->Color;

            LineItem->ZOrder=InZOrder;
            InZOrder++;

            LineItem->ClipRect=InClipArea;
            LineItem->Rect=SRect(PresentAbsPosition,PresentSize);
            PaintRenderWidget(LineItem);

        }
        else if(Item->IsA<RCanvasTriangleItem>())
        {
            CODE_BLOCK_TIME_COUNT(U"绘制三角形")

            TSharedObjectPtr<RCanvasTriangleItem> Triangle=Item;
            auto TriangleItem=std::make_shared<SRenderTriangleWidget>();
            TriangleItem->P0=Triangle->P0;
            TriangleItem->P1=Triangle->P1;
            TriangleItem->P2=Triangle->P2;
            TriangleItem->Color=Triangle->Color;

            TriangleItem->ZOrder=InZOrder;
            InZOrder++;

            TriangleItem->ClipRect=InClipArea;
            TriangleItem->Rect=SRect(PresentAbsPosition,PresentSize);
            PaintRenderWidget(TriangleItem);

        }
        else if(Item->IsA<RCanvasImageItem>())
        {
            CODE_BLOCK_TIME_COUNT(U"绘制图片")

            TSharedObjectPtr<RCanvasImageItem> Image=Item;
            auto ImageItem=std::make_shared<SRenderImageWidget>();
            // ImageItem->Position=Image->Position;
            // ImageItem->Size=Image->Size;
            ImageItem->Image=Image->Texture->GetRenderTexture();

            ImageItem->ZOrder=InZOrder;
            InZOrder++;

            ImageItem->ClipRect=InClipArea;
            ImageItem->Rect=SRect(PresentAbsPosition+Image->Position,Image->Size);
            PaintRenderWidget(ImageItem);

        }
        else if(Item->IsA<RCanvasTextItem>())
        {
            CODE_BLOCK_TIME_COUNT(U"绘制文本")

            TSharedObjectPtr<RCanvasTextItem> TextItem=Item;
         

            auto RenderTextWidget=std::make_shared<SRenderStaticTextWidget>();
            RenderTextWidget->Rect=SRect(PresentAbsPosition+TextItem->LeftTopPosition,PresentSize-TextItem->LeftTopPosition);
            RenderTextWidget->ClipRect=InClipArea;
            RenderTextWidget->ZOrder=InZOrder;
            InZOrder++;

            RenderTextWidget->TextColor= TextItem->Color;
            RenderTextWidget->CharTextures=TextItem->TextArranger.GetArrangeResult().GetRenderCharTextures();
            RenderTextWidget->CharPositions=TextItem->TextArranger.GetArrangeResult().GetCharPositions();


            // auto RenderTextWidget=std::make_shared<SRenderStaticTextWidget>();
            // RenderTextWidget->TextImage=Text->TextArranger.GetArrangeResult().WholeImage->GetRenderTexture();
            // RenderTextWidget->TextColor= Text->Color;

            // RenderTextWidget->ZOrder=InZOrder;
            // InZOrder++;
            // RenderTextWidget->ClipRect=InClipArea;
            // RenderTextWidget->Rect= SRect(
            //     Text->TextArranger.GetArrangeResult().WholeImageOffset+PresentAbsPosition+Text->LeftTopPosition
            //     ,Text->TextArranger.GetArrangeResult().WholeImageSize
            // );

            PaintRenderWidget(RenderTextWidget);
        }
        else if(Item->IsA<RCanvasColorfulTextItem>())
        {
            CODE_BLOCK_TIME_COUNT(U"绘制彩色文本")
            TSharedObjectPtr<RCanvasColorfulTextItem> TextItem=Item;


            auto RenderTextWidget=std::make_shared<SRenderDynamicTextWidget>();
            RenderTextWidget->Rect=SRect(PresentAbsPosition+TextItem->LeftTopPosition,PresentSize-TextItem->LeftTopPosition);
            RenderTextWidget->ClipRect=InClipArea;
            RenderTextWidget->ZOrder=InZOrder;
            InZOrder++;

            RenderTextWidget->CharColors=TextItem->Colors;
            RenderTextWidget->CharTextures=TextItem->TextArranger.GetArrangeResult().GetRenderCharTextures();
            RenderTextWidget->CharPositions=TextItem->TextArranger.GetArrangeResult().GetCharPositions();

            PaintRenderWidget(RenderTextWidget);
        
        }
        else if(Item->IsA<RCanvasCircleItem>())
        {
            CODE_BLOCK_TIME_COUNT(U"绘制圆形")
            TSharedObjectPtr<RCanvasCircleItem> Circle=Item;
            auto CircleItem=std::make_shared<SRenderCircleWidget>();
            CircleItem->Center=Circle->Center;
            CircleItem->Radius=Circle->Radius;
            CircleItem->Color=Circle->Color;

            CircleItem->ZOrder=InZOrder;
            InZOrder++;

            CircleItem->ClipRect=InClipArea;
            CircleItem->Rect=SRect(PresentAbsPosition,PresentSize);
            PaintRenderWidget(CircleItem);
        }
        else
        {
            assert(false);
        }

    }

}

void RCanvasWidget::Clear()
{
    LastItems=Items;
    Items.Clear();
    
}

void RCanvasWidget::AddItem(TSharedObjectPtr<RCanvasItem> Item)
{
    assert(Item);
    Items.Add(Item);
}

void RCanvasWidget::AddItems(const TVector<TSharedObjectPtr<RCanvasItem>> &InItems)
{
    Items.Append(InItems);
}

void RCanvasWidget::AddLine(const SVec2 &Start, const SVec2 &End, float LineWidth, const SColor &Color)
{
    if(Start==End)
    {
        return;
    }

    auto Item=NewObject<RCanvasLineItem>(this);
    Item->FillData(Start,End,LineWidth,Color);
    Items.Add(Item);
}

void RCanvasWidget::AddRect(const SRect &Rect, const SColor &Color)
{
    auto LineItem=NewObject<RCanvasLineItem>(this);
    auto Start=Rect.Min + SVec2(Rect.Extent.X/2, 0);
    auto End=Rect.Min + SVec2(Rect.Extent.X/2, Rect.Extent.Y);
    auto LineWidth=Rect.Extent.X;
    LineItem->FillData(
        Start,
        End,
        LineWidth,
        Color
    );
    Items.Add(LineItem);
}

void RCanvasWidget::AddTriangle(const SVec2 &P0, const SVec2 &P1, const SVec2 &P2, const SColor &Color)
{
    auto Item=NewObject<RCanvasTriangleItem>(this);
    Item->FillData(P0,P1,P2,Color);
    Items.Add(Item);
}

void RCanvasWidget::AddImage(const SVec2 &Position, const SVec2 &Size, TSharedObjectPtr<RTexture2D> Texture)
{
    auto ImageItem=NewObject<RCanvasImageItem>(this);
    ImageItem->FillData(Position,Size,Texture);
    Items.Add(ImageItem);
}

void RCanvasWidget::AddText(
    const SVec2 &Position
    , const CString &Text
    , const SColor &TextColor
    , int64_t FontSize
    , TSharedObjectPtr<RFont> InFont
    , ETextWrapMethod Wrap
    )
{
    if(Text.IsEmpty())
    {
        return;
    }

    auto _Font=InFont;
    if (!_Font)
    {
        _Font=RApplication::GetApplication()->GetSubsystem<RFontApplicationSubsystem>()->GetDefaultFont();
    }

    //arrange text
    STextArrangePapameters Params;
    Params.Font=_Font;
    Params.FontSize=FontSize;
    Params.Text=Text;
    Params.Wrap=Wrap;
    Params.PaintAreaSize.X=std::numeric_limits<float>::max();
    Params.PaintAreaSize.Y=std::numeric_limits<float>::max();

    auto TextItem=NewObject<RCanvasTextItem>(this);
    TextItem->TextArranger.ArrangeText(Params);
    TextItem->Color=TextColor;
    TextItem->LeftTopPosition=Position;
#ifdef DEBUG
    TextItem->Text=Text;
#endif

    Items.Add(TextItem);
}

TSharedObjectPtr<RCanvasItem> RCanvasWidget::AddTextWithAlignment(const SRect &TextRect, const CString &Text, const SColor &TextColor, int64_t FontSize, ETextHorizontalAlignment HorizontalAlignment, ETextVerticalAlignment VerticalAlignment, TSharedObjectPtr<RFont> Font)
{
    if(Text.IsEmpty())
    {
        return nullptr;
    }

    auto _Font=Font;
    if (!_Font)
    {
        _Font=RApplication::GetApplication()->GetSubsystem<RFontApplicationSubsystem>()->GetDefaultFont();
    }

    //arrange text
    STextArrangePapameters Params;
    Params.Font=_Font;
    Params.FontSize=FontSize;
    Params.Text=Text;
    Params.Wrap=ETextWrapMethod::WrapAtLineEnd;
    Params.PaintAreaSize=TextRect.Extent;
    Params.HorizontalAlign=HorizontalAlignment;
    Params.VerticalAlign=VerticalAlignment;


    auto TextItem=NewObject<RCanvasTextItem>(this);
    TextItem->TextArranger.ArrangeText(Params);
    TextItem->Color=TextColor;
    TextItem->LeftTopPosition=TextRect.Min;
#ifdef DEBUG
    TextItem->Text=Text;
#endif

    Items.Add(TextItem);

    return TextItem;
}

TSharedObjectPtr<RCanvasItem> RCanvasWidget::AddColorfulText(const SVec2 &LeftTopPosition, const CString &Text, const TVector<SColorfulTextColor> &Colors, int64_t FontSize, TSharedObjectPtr<RFont> Font)
{
    if(Text.IsEmpty())
    {
        return {};
    }

    auto _Font=Font;
    if (!_Font)
    {
        _Font=RApplication::GetApplication()->GetSubsystem<RFontApplicationSubsystem>()->GetDefaultFont();
    }

    //arrange text
    STextArrangePapameters Params;
    Params.Font=_Font;
    Params.FontSize=FontSize;
    Params.Text=Text;
    Params.Wrap=ETextWrapMethod::WrapAtLineEnd;
    Params.PaintAreaSize.X=std::numeric_limits<float>::max();
    Params.PaintAreaSize.Y=std::numeric_limits<float>::max();;

    auto TextItem=NewObject<RCanvasColorfulTextItem>(this);
    TextItem->LeftTopPosition=LeftTopPosition;
    TextItem->TextArranger.ArrangeText(Params);
    TextItem->Colors.Reserve(TextItem->TextArranger.GetArrangeResult().GetRenderCharCount());

    for(int64_t ColorIndex=0;ColorIndex<Colors.Num();++ColorIndex)
    {
        auto& ColorfulTextColor=Colors[ColorIndex];
        int64_t StartIndex=ColorfulTextColor.StartIndex;
        int64_t EndIndex=((ColorIndex+1)<Colors.Num())?(Colors[ColorIndex+1].StartIndex):(Text.GetLength());
        assert(StartIndex<EndIndex);

        for(int64_t i=StartIndex;i<EndIndex;++i)
        {
            if(!TextItem->TextArranger.GetArrangeResult().IsCharRendered(i))
            {
                continue;
            }
            TextItem->Colors.Add(ColorfulTextColor.Color);
        }
    }
        
#ifdef DEBUG
    TextItem->Text=Text;
#endif

    Items.Add(TextItem);
    return TextItem;
      
}

void RCanvasWidget::AddCircle(const SVec2 &Center, float Radius, const SColor &Color)
{
    auto Item=NewObject<RCanvasCircleItem>(this);
    Item->FillData(Center,Radius,Color);
    Items.Add(Item);
}

void RCanvasLineItem::FillData(const SVec2 & InStart, const SVec2 & InEnd, float InLineWidth, const SColor & InColor)
{
    Start=InStart;
    End=InEnd;
    LineWidth=InLineWidth;
    Color=InColor;
}


void RCanvasTriangleItem::FillData(
    const SVec2 &InP0, 
    const SVec2 &InP1, 
    const SVec2 &InP2, 
    const SColor &InColor)
{
    P0=InP0;
    P1=InP1;
    P2=InP2;
    Color=InColor;
}

void RCanvasImageItem::FillData(
    const SVec2 &InPosition
    , const SVec2 &InSize
    , TSharedObjectPtr<RTexture2D> InTexture)
{
    Position=InPosition;
    Size=InSize;
    Texture=InTexture;
}

void RCanvasCircleItem::FillData(
    const SVec2 &InCenter,
    float InRadius,
    const SColor &InColor)
{
    Center=InCenter;
    Radius=InRadius;
    Color=InColor;
}
